package org.zero.onlinesubject.utils;

import org.zero.onlinesubject.common.param.Node;

import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.nio.charset.StandardCharsets;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

public class WordUtil {
    private static List<String> sentiveWords;
    private static final Map<Character, Node> root = new HashMap<>();

    public static void init(List<String> words){
        sentiveWords = words;
        fillRoots();
    }

    // 添加词语到敏感词库
    public static void addWord(String word){
        fillNode(root,word,0);
    }

    // 获取文本内容
    public static String getFileContent(String filename){
        String text = null;
        try(
                InputStream is = WordUtil.class.getClassLoader().getResourceAsStream(filename);
                BufferedReader reader = new BufferedReader(new InputStreamReader(is, StandardCharsets.UTF_8)))
        {
            StringBuilder builder = new StringBuilder();
            String line;
            while((line = reader.readLine())!=null){
                builder.append(line);
            }
            text = builder.toString();
            text = text.substring(0,text.length()-1);
        }catch(Exception ex) {
            ex.printStackTrace();
        }
        return text;
    }
    // 敏感词替换字符
    private static String replaceWords(int len){
        StringBuilder builder = new StringBuilder();
        for (int i = 0; i < len; i++) {
            builder.append("*");
        }
        return builder.toString();
    }

    // 生成敏感词树
    private static void fillRoots(){
        for (String word : sentiveWords) {
            fillNode(root,word,0);
        }
    }

    // 填充节点
    private static void fillNode(Map<Character,Node> nodes,String word,int idx){
        if(word.length() <= idx) return;

        char c = word.charAt(idx);
        // 不存在的话就创建该节点
        if (!nodes.containsKey(c)) {
            Node node = new Node();
            node.setPart(c);
            boolean flag = word.length()-1 == idx;
            node.setIsEnd(flag);
            if(!flag){
                node.setLen(0);
            }else{
                node.setLen(idx + 1);
            }
            node.setNodes(new HashMap<>());
            nodes.put(c,node);
        }
        // 在该节点深度的基础之上进行叠加
        Node node = nodes.get(c);
        fillNode(node.getNodes(),word,idx+1);
    }

    // 去除敏感词
    public static String removeSentiveWords(String text){
        for (int i = 0; i < text.length(); i++) {
            char c = text.charAt(i);
            if(!root.containsKey(c)) continue;

            Node node = root.get(c);
            int len = getMatchLength(text,i+1,node.getNodes());
            int end = i + len;
            text = text.substring(0,i) + replaceWords(len) + text.substring(end);
            if(len!=0){
                i += len - 1;
            }
        }
        return text;
    }

    // 获取匹配内容长度
    /**
     *      1. 情况一: 敏感词长度小于内容长度则能匹配到对应关键词
     *          例子： 日你大爷的
     *          敏感词：日你大爷
     *          Node node = map.get(c);
     *          1.1 node == null return 0;
     *          1.2 node !=null:
     *             1.2.1 node.getNodes() == null;
     *                      isEnd = true; return max(node,getLen(),recursion(text,idx+1,node.getNodes());
     *                      isEnd = false; return recursion(text,idx+1,node.getNodes())
     *             1.2.2 node.getNodes() !=null;
     *                      isEnd = true; return max(node,getLen(),recursion(text,idx+1,node.getNodes());
     *                      isEnd = false; return recursion(text,idx+1,node.getNodes())
     *            ---- 本源：
     *             1.2.1 isEnd = true;
     *                      return max(node,getLen(),recursion(text,idx+1,node.getNodes());
     *             1.2.2 isEnd = false;
     *                      return recursion(text,idx+1,node.getNodes());
     *      2. 情况二: 内容长度小于可匹配到的敏感词最小长度
     *          例子： 日你
     *          敏感词： 日你大爷
     */
    private static int getMatchLength(String text,int idx,Map<Character,Node> map){
        if(map==null) return 0;
        if(idx > text.length()-1) return 0;

        char c = text.charAt(idx);
        Node node = map.get(c);
        if(node == null) return 0;

        if(node.getIsEnd()){
            return Math.max(node.getLen(),getMatchLength(text,idx+1,node.getNodes()));
        }else{
            return getMatchLength(text,idx+1,node.getNodes());
        }
    }
}
